//      mp.h
//      
//      Copyright 2012 tqlong <tqlong@espada>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#ifndef __MATCHING_PURSUIT_H
#define __MATCHING_PURSUIT_H
#include <set>
#include <boost/program_options.hpp>
#include "stl-helper.h"
#include "data.h"

class MP_SqLoss {
  MatrixData& data_;
  arma::vec w_;
  std::set<int> selected_feature_;
 public:
 MP_SqLoss(MatrixData& data) 
   : data_(data) {}
  void solve();
  void print_result(const std::string& outputFile);
  
  const arma::vec& result() const { return w_; } 

  std::string debugFile_;
 protected:
  int maxip(const arma::vec& q);
  void build_data(arma::mat& X);
  void solve_model(const arma::mat& X, arma::vec& r);
};

class MP_LogLoss {
 protected:
  MatrixData& data_;
  arma::vec w_;
  std::set<int> selected_feature_;
  boost::program_options::variables_map& vm_;
 public:
  double C_;
 public:
 MP_LogLoss(MatrixData& data, boost::program_options::variables_map& vm) 
   : data_(data), vm_(vm), C_(100) {}
  void solve();
  void print_result(const std::string& outputFile);
  arma::vec classify(MatrixData& test);
  
  const arma::vec& result() const { return w_; } 
	const std::set<int> selected_feature() const { return selected_feature_; }

  std::string debugFile_;
 protected:
  int maxip(const arma::vec& q);
  void build_data(arma::mat& X);
  void solve_model(const arma::mat& X, arma::vec& r);
  void fval_gradient(const arma::mat& X, const arma::vec& w, 
		     arma::vec& f, arma::vec& e, arma::vec& p, double& f_val);
};

class MP_SqHingeLoss : public MP_LogLoss {
 public:
 MP_SqHingeLoss(MatrixData& data, boost::program_options::variables_map& vm) 
   : MP_LogLoss(data, vm) {}
  void solve();
  
 protected:
  void solve_model(const arma::mat& X, arma::vec& r);
  void fval_gradient(const arma::mat& X, const arma::vec& w, 
		     arma::vec& f, arma::vec& e, arma::vec& p, double& f_val);
};

class MP_SmoothHingeLoss : public MP_LogLoss {
 public:
 MP_SmoothHingeLoss(MatrixData& data, boost::program_options::variables_map& vm) 
   : MP_LogLoss(data, vm), mu_(0.1) {}
  void solve();
	void solve_all_feature();
  
 protected:
  void solve_model(const arma::mat& X, arma::vec& r);
  void fval_gradient(const arma::mat& X, const arma::vec& w, 
		     arma::vec& f, arma::vec& e, arma::vec& p, double& f_val);
 public:
  double mu_;
};

#endif
